﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using GalaSoft.MvvmLight;
using System.Collections;
using System.Diagnostics;
using System.Xml.Linq;
using System.Collections.ObjectModel;
using LogViewApp.Models;
using System.Collections.Generic;
using GalaSoft.MvvmLight.Command;
using System.ComponentModel;
using System.Threading;
using System.Linq;
using LogViewApp.ServiceReference1;

namespace LogViewApp.ViewModel
{
    public class LogViewModel : ViewModelBase
    {
        private string xmlFileName = null;
        private XElement xLogRoot = null;

        private string _LogKeyWordFilter = null;

        public string LogKeyWordFilter
        {
            get
            {
                return _LogKeyWordFilter;
            }
            set
            {
                if (_LogKeyWordFilter == value)
                    return;
                _LogKeyWordFilter = value;
                RaisePropertyChanged("LogKeyWordFilter");
            }
        }
        private string _MessageKeyWordFilter;
        public string MessageKeyWordFilter
        {
            get
            {
                return _MessageKeyWordFilter;
            }
            set
            {
                if (_MessageKeyWordFilter == value)
                    return;
                _MessageKeyWordFilter = value;
                RaisePropertyChanged("MessageKeyWordFilter");
            }
        }

        private string _ErrorLevelFilter;
        
        public string ErrorLevelFilter 
        { 
            get
            {
                return _ErrorLevelFilter;
            }
            set
            {
                if (_ErrorLevelFilter == value)
                    return;
                _ErrorLevelFilter = value;
                RaisePropertyChanged("ErrorLevelFilter");
            }
        }

        private string _SenderNameFilter;
        public string SenderNameFilter
        {
            get
            {
                return _SenderNameFilter;
            }
            set
            {
                if (_SenderNameFilter == value)
                    return;
                _SenderNameFilter = value;
                Debug.WriteLine("SenderNameFilter is updated to " + _SenderNameFilter);
                RaisePropertyChanged("SenderNameFilter");
            }
        }

        public void ParseUri(string LogQueryString, string guidString)
        {
            xmlFileName = LogQueryString;
            Guid guid;
            if (Guid.TryParse(guidString, out guid))
            {
                xLogRoot = GetMainPage().GetLogFileXElementByGuid(guid);
            }

        }

        internal MainPage GetMainPage()
        {
            Activity act = Application.Current.RootVisual as Activity;
            MainPage mainPage = act.Content as MainPage;
            return mainPage;
        }

        public IQueryable<LogItem> logItems{get;set;}

        private IQueryable<LogItem> _logItemsShowInGrid;
        public IQueryable<LogItem> logItemsShowInGrid 
        {
            get
            {
                return _logItemsShowInGrid;
            }
            set
            {
                if (_logItemsShowInGrid == value)
                    return;
                _logItemsShowInGrid = value;
                RaisePropertyChanged("logItemsShowInGrid");
            }
        }

        private RelayCommand _FilterUpdateCmd;
        public RelayCommand FilterUpdateCmd
        {
            get
            {
                if (_FilterUpdateCmd == null)
                {
                    _FilterUpdateCmd = new RelayCommand(() =>
                    {
                        UpdateFilterResult();
                    });
                }
                return _FilterUpdateCmd;
            }
        }

        private RelayCommand _FilterUploadCmd;
        public RelayCommand FilterUploadCmd
        {
            get
            {
                if (_FilterUploadCmd == null)
                {
                    _FilterUploadCmd = new RelayCommand(() =>
                    {
                        BackgroundWorker worker = new BackgroundWorker();
                        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
                        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((so,ar)=>
                        {
                            Debug.WriteLine("Background Thread Completed");
                        }
                        );
                        worker.WorkerReportsProgress = true;
                        worker.ProgressChanged += new ProgressChangedEventHandler((so, ar) =>
                        {
                            GetMainPage().ProgressChangeText.Text = ar.ProgressPercentage.ToString();

                        });
                        worker.RunWorkerAsync();
                    });
                }
                return _FilterUploadCmd;
            }
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            var client = new ServiceClient();

            client.UploadOneLogCompleted += (se, ar) =>
            {
                if (ar.Error == null)
                {

                    Debug.WriteLine("Return from WCF. Uploaded log timestampe is " + ar.Result);

                    autoEvent.Set();
                }
            };

            int logCount = logItems.Count();
            int currentLogNumber = 0;
            foreach (var log in logItems)
            {
                
                Debug.WriteLine("Ready to call WCF. Uploading log timestampe is " + log.Time + "  message size is " + log.WholeLog.Length);
                if (log.WholeLog.Length < 9000)
                {
                    client.UploadOneLogAsync(log);
                    autoEvent.WaitOne();
                }
                BackgroundWorker worker = sender as BackgroundWorker;
                worker.ReportProgress(++currentLogNumber * 100 / logCount);
            }
        }

        static AutoResetEvent autoEvent = new AutoResetEvent(false);

        static private string ProcessXml(XElement xLogRoot, out IQueryable<LogItem> iQueryablelogItems)
        {
            List<LogItem> logItems = new List<LogItem>();
            iQueryablelogItems = null;
            string returnString = string.Empty;
            try
            {

                XElement xLogFile = xLogRoot;
                XAttribute xVersion = xLogFile.Attribute("Version");
                string version = "1.0";
                if (xVersion == null)//this is the first version, let's say version 1
                {
                    version = "1.0";
                }
                else
                {
                    version = xVersion.Value;
                }
                if (version == "1.0")
                {
                    var xLogItems = xLogFile.Elements("Log");
                    foreach (XElement xLogItem in xLogItems)
                    {
                        string error = string.Empty;
                        string Sender = string.Empty;
                        string Level = string.Empty;
                        string Time = string.Empty;
                        string Message = string.Empty;
                        string WholeLog = string.Empty;
                        LogItem logItem;
                        try
                        {
                            Sender = xLogItem.Attribute("Sender").Value;
                            Level = xLogItem.Attribute("Level").Value;
                            Time = xLogItem.Attribute("Time").Value;
                            Message = xLogItem.Attribute("Message").Value;
                            WholeLog = xLogItem.ToString();
                        }
                        catch (Exception exp)
                        {
                            error = exp.Message;
                        }
                        try
                        {
                            logItem = new LogItem { Sender = Sender, error = error, Level = Level, Message = Message, Time = Time, WholeLog = WholeLog };
                            logItems.Add(logItem);
                            
                        }
                        catch (Exception exp)
                        {
                            returnString += exp.Message;
                            returnString += "\r\n";
                            continue;
                        }
                    }

                    iQueryablelogItems = logItems.AsQueryable<LogItem>();
                    return returnString;
                }
                else
                {
                    return "Version" + version + " is not supported yet";
                }
            }
            catch (Exception exp)
            {
                return returnString + exp.Message;
            }

        }


        static public TreeViewItem CreateTreeView(XElement xTemp)
        {
            TreeViewItem item = new TreeViewItem();
            string headerString = xTemp.Name.LocalName;
            var attrs = xTemp.Attributes();
            foreach (var attr in attrs)
            {
                string attributestring = string.Format("\r\n\t{0}={1}", attr.Name.LocalName, attr.Value);
                headerString += attributestring;
            }
            item.Header = headerString;

            var elements = xTemp.Elements();
            foreach (var element in elements)
            {
                TreeViewItem child = new TreeViewItem();
                child = CreateTreeView(element);
                item.Items.Add(child);
            }
            return item;
        }




        internal void UpdateDataAsync()
        {
            if (xmlFileName == null || xLogRoot == null)
                return;

            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler((o, e) =>
                {
                    IQueryable<LogItem> _logItems = null;
                    XElement _xLogRoot = e.Argument as XElement;
                    if (xLogRoot == null)
                        return;

                    string result = ProcessXml(_xLogRoot, out _logItems);
                    if (result != string.Empty)
                    {
                        e.Result = result;
                    }
                    else
                    {
                        e.Result = _logItems;
                        
                    }
                });

            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((o, e) =>
                {
                    IQueryable<LogItem> result = e.Result as IQueryable<LogItem>;
                    if (result == null)
                    {
                        string errorString = e.Result as string;
                        if (errorString != null)
                            MessageBox.Show(errorString);
                    }
                    else
                    {
                        
                        if (logItems == null || logItems.Count<LogItem>() == 0)
                        {
                            logItems = result;
                        }
                        logItemsShowInGrid = result;
                    }
                });
            worker.RunWorkerAsync(xLogRoot);
        }

        internal void UpdateFilterResult()
        {
            if (logItems == null || logItems.Count<LogItem>() == 0)
                return;
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler((o, e) =>
            {
                IQueryable<LogItem> FilterResult = DoFilter();
                e.Result = FilterResult;
            });

            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((o, e) =>
            {
                IQueryable<LogItem> result = e.Result as IQueryable<LogItem>;
                if (result == null)
                {
                    string errorString = e.Result as string;
                    if (errorString != null)
                        MessageBox.Show(errorString);
                }
                else
                {
                    logItemsShowInGrid = result;
                }
            });
            worker.RunWorkerAsync(xLogRoot);
        }

        private IQueryable<LogItem> DoFilter()
        {
            if (logItems == null || logItems.Count<LogItem>() == 0)
                return null;

            var temp = logItems;
            if (string.IsNullOrEmpty(LogKeyWordFilter) == false)
            {
                temp = from log in temp where log.WholeLog.Contains(LogKeyWordFilter) select log;
            }
            if (string.IsNullOrEmpty(MessageKeyWordFilter) == false)
            {
                temp = from log in temp where log.Message.Contains(MessageKeyWordFilter) select log;
            }
            if (string.IsNullOrEmpty(SenderNameFilter) == false)
            {
                temp = from log in temp where log.Sender.Contains(SenderNameFilter) select log;
            }
            if (string.IsNullOrEmpty(ErrorLevelFilter) == false)
            {
                temp = from log in temp where log.Level.Equals(ErrorLevelFilter) select log;
            }
            return temp;
        }
    }

}
